from __future__ import absolute_import
import shutil
import logging

from solv import Repo, Dataiterator
import solv
import os

from pkgr.repos.remote import RepoRemote

logger = logging.getLogger('pkgr.repos.Rpm')
from pkgr.groups import Groups


class RepoRepomd(RepoRemote):
    groups = None
    
    def _load_groups(self):
        logger.debug('%s: Loading groups...', self)
        groupscache = self.join_cache_dir('groups-%s.xml' % self.get_name())
        
        if self.is_expired() or not os.path.exists(groupscache):
            # cache the groups as well. libsolv doesnt do groups?
            filename, chksum = self.find('group')
            if not filename:
                logger.debug('%s Repo doesnt have group file.', self)
                return
                
            groupfile = self.download_repo_file(filename, chksum, False)
            
            if not groupfile:
                logger.debug('%s Repo doesnt have group file.', self)
                return
            
            shutil.copy(groupfile.name, groupscache)
        
        groupsxml = open(groupscache).read()
        #logging.debug('Parsing groups xml: %s', groupsxml)
        self.groups = Groups.from_xml(groupsxml)
        #print self.groups.get_groups()
    
    def get_cachepath(self):
        return self.join_cache_dir('repomd-%s.xml' % self.get_name())
    

    _expired = True

    def set_expired(self, b):
        self._expired = b
        
    def is_expired(self):
        return self._expired is True
        
    def load_if_changed(self):
        # TODO: only get if expired
        logger.debug('Loading if changed: %s', self)
        
        repomdcache = self.get_cachepath()
        expired = self.is_cache_expired()
        
        self.set_expired(expired)
        
        if expired:
            logger.debug('Expired repomd.xml. Downloading...')
            f = self.download_repo_file("repodata/repomd.xml", None, False)
            logger.debug('Writing repomd cache to %s', repomdcache)
            fc = open(repomdcache, 'wb')
            fc.write(f.read())
            fc.close()
            f.close()
        
        fc = open(repomdcache, 'rb')
        # turn the file handle into some for libsolv
        f = self.xlat_filehandle(fc)
        
        if not f:
            raise Exception("Repository could not be loaded. repomd.xml file not on servers.")
            logger.warn("no repomd.xml file, skipped")
            self.get_libsolv_repo().free(True)
            del self.handle
            return False
            
        self._repo.add_repomdxml(f, solv.Repo.REPO_USE_ROOTDIR)
        self._load_groups()
        
        #solv.xfclose(f)
        
        if not self.is_expired():
            logger.info('%s: Using cached solv', self)
            self._load_solv_repo(self.cachepath(), None, self._repo.first_repodata())
            return
            
        logger.debug('Downloading primarydb for %s', self.get_name())
        
        # primary db is required
        (filename, filechksum) = self.find('primary')
        if not filename:
            raise Exception("no primary db filename")
          
        f = self.download_repo_file(filename, filechksum)
        # turn the file handle into some for libsolv
        f = self.xlat_filehandle(f, filename, True)
        if not f:
            raise Exception("Error downloading primary db")
            
        self._repo.add_rpmmd(f, None, solv.Repo.REPO_USE_ROOTDIR|(1 << 8))
        #solv.xfclose(f)
        
        # add extensions
        repodata = self._repo.add_repodata(0)
        self.load_filelists(repodata)
        self.load_deltainfo(repodata)
        repodata.internalize()
        
        logger.debug('Done loading.. writing cached...')
        # TODO: only write if expired
        self.writecachedrepo(None)
        # must be called after writing the repo
        self._repo.create_stubs()
        '''
        (filename, filechksum) = self.find('updateinfo')
        if filename:
            f = self.download(filename, True, filechksum, True)
            if f:
                self.get_libsolv_repo().add_updateinfoxml(f, 0)
                solv.xfclose(f)
        
        '''
        return True

    def find(self, what):
        di = self._repo.Dataiterator(solv.SOLVID_META, solv.REPOSITORY_REPOMD_TYPE, what,
                                                 Dataiterator.SEARCH_STRING)
        di.prepend_keyname(solv.REPOSITORY_REPOMD)
        for d in di:
	    dp = d.parentpos()
            filename = dp.lookup_str(solv.REPOSITORY_REPOMD_LOCATION)
            chksum = dp.lookup_checksum(solv.REPOSITORY_REPOMD_CHECKSUM)
            if filename and not chksum:
                logger.warn('No file checksum %s', filename)
                filename = None
                chksum = None
            if filename:
                return (filename, chksum)
        return (None, None)
        
    def get_groups(self):
        return self.groups
        
    def load_ext(self, repodata):
        """ Load repository "extensions". ie, filelists, deltainfo
        """
        if not self.is_expired():
            logger.warn('skipping load of ext %s', repodata)
            return
        
        logger.debug('Loading additional repository metadata: %s', repodata)
        
        repomdtype = repodata.lookup_str(solv.SOLVID_META, solv.REPOSITORY_REPOMD_TYPE)
        if repomdtype == 'filelists':
            ext = 'FL'
        elif repomdtype == 'deltainfo':
            ext = 'DL'
        else:
            return False
        
        # XXX: remove this when expiration is handled
        #if self.usecachedrepo(ext):
        #    logger.debug('Using cached repo extensions %s, %s', self.name, ext)
        #    return True
        logger.debug('Downloading repo metadata %s [%s]', ext, self.name)
        filename = repodata.lookup_str(solv.SOLVID_META, solv.REPOSITORY_REPOMD_LOCATION)
        filechksum = repodata.lookup_checksum(solv.SOLVID_META, solv.REPOSITORY_REPOMD_CHECKSUM)
        f = self.download(filename, True, filechksum)
        if not f:
            return False
        if ext == 'FL':
            self._repo.add_rpmmd(f, 'FL', Repo.REPO_USE_LOADING | Repo.REPO_EXTEND_SOLVABLES)
        elif ext == 'DL':
            self._repo.add_deltainfoxml(f, Repo.REPO_USE_LOADING)
        #solv.xfclose(f)
        logger.debug('Writing cache repo metadata: %s %s', ext, repodata)
        self.writecachedrepo(ext, repodata)
        return True
        
    def load_filelists(self, repodata):
        if not self.is_expired():
            logger.warn('skipping load of filelists %s', repodata)
            return
        what = 'filelists'
        ext = 'FL'
        
        logger.debug('Loading filelists %s [%s]', repodata, self)
        filename, chksum = self.find(what)
        if not filename and what == 'deltainfo':
            filename, chksum = self.find('prestodelta')
        if not filename:
            return
        handle = repodata.new_handle()
        repodata.set_poolstr(handle, solv.REPOSITORY_REPOMD_TYPE, what)
        repodata.set_str(handle, solv.REPOSITORY_REPOMD_LOCATION, filename)
        repodata.set_checksum(handle, solv.REPOSITORY_REPOMD_CHECKSUM, chksum)
        if ext == 'DL':
            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOSITORY_DELTAINFO)
            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOKEY_TYPE_FLEXARRAY)
        elif ext == 'FL':
            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.SOLVABLE_FILELIST)
            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOKEY_TYPE_DIRSTRARRAY)
        repodata.add_flexarray(solv.SOLVID_META, solv.REPOSITORY_EXTERNAL, handle)
    
    def load_deltainfo(self, repodata):
        if not self.is_expired():
            logger.warn('skipping load of deltainfo %s', repodata)
            return
        #self.add_ext(repodata, 'deltainfo', 'DL')
        what = 'deltainfo'
        ext = 'DL'
        
        logger.debug('Loading deltainfo %s %s %s', repodata, what, ext)
        filename, chksum = self.find(what)
        if not filename and what == 'deltainfo':
            filename, chksum = self.find('prestodelta')
        if not filename:
            return
        handle = repodata.new_handle()
        repodata.set_poolstr(handle, solv.REPOSITORY_REPOMD_TYPE, what)
        repodata.set_str(handle, solv.REPOSITORY_REPOMD_LOCATION, filename)
        repodata.set_checksum(handle, solv.REPOSITORY_REPOMD_CHECKSUM, chksum)
        ## delta handling
        repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOSITORY_DELTAINFO)
        repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOKEY_TYPE_FLEXARRAY)
        
        repodata.add_flexarray(solv.SOLVID_META, solv.REPOSITORY_EXTERNAL, handle)
        
        
#logger.debug('Downloading groups %s, %s', self.name, ext)
#filename = repodata.lookup_str(solv.SOLVID_META, solv.REPOSITORY_REPOMD_LOCATION)
#filechksum = repodata.lookup_checksum(solv.SOLVID_META, solv.REPOSITORY_REPOMD_CHECKSUM)

#f = self.download('groups', True, filechksum)
#return True
